﻿// Copyright (C) 2012 Jeff Tanner <jeff00seattle@gmail.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

using System;
using System.IO;
using System.Configuration;
using System.Diagnostics;

using WindowsAzure_FileBackup_Common;
using WindowsAzure_REST;

namespace WindowsAzure_FileBackup_Service
{
    public partial class Service : System.ServiceProcess.ServiceBase
    {
        public string Filter { get; set; }
        public bool IncludeSubDirs { get; set; }

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        private Common common = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="Service"/> class.
        /// </summary>
        public Service()
        {
            this.initialize();
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            System.ServiceProcess.ServiceBase[] ServicesToRun;
            // Change the following line to match.
            ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service() };
            System.ServiceProcess.ServiceBase.Run(ServicesToRun);
        }

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void initialize()
        {
            this.common = new Common();

            ((System.ComponentModel.ISupportInitialize)(this.common.FileMonitor)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.common.EventLog)).BeginInit();


            // 
            // _fileMonitor
            // 
            this.common.FileMonitor.EnableRaisingEvents = true;
            this.common.FileMonitor.NotifyFilter = ((System.IO.NotifyFilters)((((((System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName)
                        | System.IO.NotifyFilters.Attributes)
                        | System.IO.NotifyFilters.Size)
                        | System.IO.NotifyFilters.LastWrite)
                        | System.IO.NotifyFilters.CreationTime)));
            this.common.FileMonitor.Changed += new System.IO.FileSystemEventHandler(this.common.FileMonitor_OnChanged);
            this.common.FileMonitor.Created += new System.IO.FileSystemEventHandler(this.common.FileMonitor_OnChanged);
            this.common.FileMonitor.Deleted += new System.IO.FileSystemEventHandler(this.common.FileMonitor_OnChanged);
            this.common.FileMonitor.Error += new System.IO.ErrorEventHandler(this.common.FileMonitor_OnError);
            this.common.FileMonitor.Renamed += new System.IO.RenamedEventHandler(this.common.FileMonitor_OnRenamed);

            // 
            // WindowsAzure_FileBackup
            // 
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.ServiceName = ConfigurationManager.AppSettings.Get("ServiceName").ToString();

            ((System.ComponentModel.ISupportInitialize)(this.common.FileMonitor)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.common.EventLog)).EndInit();

        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }

            base.Dispose(disposing);
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Start command is sent to the service 
        /// by the Service Control Manager (SCM) or when the operating system starts (for a service 
        /// that starts automatically). Specifies actions to take when the service starts.
        /// </summary>
        /// <param name="args">Data passed by the start command.</param>
        protected override void OnStart(string[] args)
        {
            this.common.EventLog.WriteEntry("OnStart");

            try
            {
                //retrieve the configuration properties from the Machine.config file.
                this.Filter = ConfigurationManager.AppSettings.Get("WindowsAzureFileBackupSvcFilter").ToString();
                this.IncludeSubDirs = (Convert.ToBoolean(ConfigurationManager.AppSettings.Get("WindowsAzureFileBackupSvcIncludeSubDirs").ToString()));

                if (string.IsNullOrEmpty(Common.WindowsAzureFileBackupRootDir))
                {
                    string errorMsg = "OnStart: Directory path is not defined";

                    this.common.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                if (!Directory.Exists(Common.WindowsAzureFileBackupRootDir))
                {
                    string errorMsg = String.Format("OnStart: Directory path is not valid '{0}'", Common.WindowsAzureFileBackupRootDir);

                    this.common.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                //Set the path for the FileSystemWatcher to monitor.
                this.common.FileMonitor.Path = Common.WindowsAzureFileBackupRootDir;
                //Set the file type filter for the FileSystemWatcher to monitor.
                this.common.FileMonitor.Filter = this.Filter;
                //Determine if the FileSystemWatcher should monitor subdirectories.
                this.common.FileMonitor.IncludeSubdirectories = this.IncludeSubDirs;

                //Set the NotifyFilters for raising events.
                this.common.FileMonitor.NotifyFilter
                    = NotifyFilters.LastAccess |
                      NotifyFilters.LastWrite |
                      NotifyFilters.FileName |
                      NotifyFilters.DirectoryName |
                      NotifyFilters.Attributes |
                      NotifyFilters.Size |
                      NotifyFilters.CreationTime;

                //Begin monitoring.
                this.common.FileMonitor.EnableRaisingEvents = true;

                Common.BlobREST.CreateContainer(Common.WindowsAzureStorageBlobContainerName);

                this.common.BlobContainerCreate();

                DirectoryInfo dirInfo = new DirectoryInfo(Common.WindowsAzureFileBackupRootDir.Replace(@"\", @"\\"));
                this.common.BackupDirectory(dirInfo);
            }
            catch (System.ApplicationException ex)
            {
                this.common.EventLog.WriteEntry(
                    String.Format("OnContinue | ApplicationException: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
            catch (Exception ex)
            {
                this.common.EventLog.WriteEntry(
                    String.Format("OnStart | Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Stop command is sent 
        /// to the service by the Service Control Manager (SCM). Specifies actions to 
        /// take when a service stops running.
        /// </summary>
        protected override void OnStop()
        {
            this.common.EventLog.WriteEntry("OnStop");

            //When the service is stopped the FileSystemMonitor should stop raising events.
            this.common.FileMonitor.EnableRaisingEvents = false;
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Pause command is sent 
        /// to the service by the Service Control Manager (SCM). Specifies actions to 
        /// take when a service pauses.
        /// </summary>
        protected override void OnPause()
        {
            this.common.EventLog.WriteEntry("OnPause");

            //When the service is paused the FileSystemMonitor should stop raising events.
            this.common.FileMonitor.EnableRaisingEvents = false;
        }

        /// <summary>
        /// When implemented in a derived class, <see cref="M:System.ServiceProcess.ServiceBase.OnContinue"/> runs when a Continue command is sent to the service by the Service Control Manager (SCM). Specifies actions to take when a service resumes normal functioning after being paused.
        /// </summary>
        protected override void OnContinue()
        {
            try
            {
                this.common.EventLog.WriteEntry("OnContinue.");

                //When the service is continued, then retrieve the configuration properties again.
                this.Filter = ConfigurationManager.AppSettings.Get("WindowsAzureFileBackupSvcFilter").ToString();
                this.IncludeSubDirs = (Convert.ToBoolean(ConfigurationManager.AppSettings.Get("WindowsAzureFileBackupSvcIncludeSubDirs").ToString()));

                if (string.IsNullOrEmpty(Common.WindowsAzureFileBackupRootDir))
                {
                    string errorMsg = "OnContinue: Directory path is not defined";

                    this.common.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                if (!Directory.Exists(Common.WindowsAzureFileBackupRootDir))
                {
                    string errorMsg = String.Format("OnContinue: Directory path is not valid '{0}'", Common.WindowsAzureFileBackupRootDir);

                    this.common.EventLog.WriteEntry(
                        errorMsg,
                        EventLogEntryType.Error
                        );

                    throw new ApplicationException(errorMsg);
                }

                //Set the properties on the monitor.
                this.common.FileMonitor.Path = Common.WindowsAzureFileBackupRootDir;
                this.common.FileMonitor.Filter = this.Filter;
                this.common.FileMonitor.IncludeSubdirectories = this.IncludeSubDirs;
            }
            catch (System.ApplicationException ex)
            {
                this.common.EventLog.WriteEntry(
                    String.Format("OnContinue | ApplicationException: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
            catch (Exception ex)
            {
                this.common.EventLog.WriteEntry(
                    String.Format("OnContinue | Exception: {0}", ex.Message),
                    EventLogEntryType.Error
                    );
            }
        }
    }
}
